package fem2d;

import java.io.IOException;
import java.util.ArrayList;

import math2.ConstantFunctionRnToR;
import math2.FunctionRnToR;
import fem2.AbstractStructuralStaticDemo;
import fem2.Constraint;
import fem2.Debugger;
import fem2.DistributedLoad;
import fem2.Element;
import fem2.Face;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshGenerator;
import fem2.MeshPart;
import fem2.MeshUtilities;
import fem2.Model;
import fem2.Node;
import fem2.analysis.Analysis;
import fem2.analysis.LinearStaticAnalysis;
import fem2.element.StructuralElement;
import fem2.enu.EchoLevelType;
import fem2.enu.State;
import fem2.material.StVenantKirchhoffMM;
import fem2.pre_and_post.GidPostStructural;
import fem2.pre_and_post.PatchMeshGenerator;

public class Excavation2dDeactivation extends AbstractStructuralStaticDemo {

	private int number_of_vertical_sections = 7;
	private int number_of_horizontal_sections = 13;
	private double dx = 1;
	private double dy = 1;
	private double x0 = 0.0;
	private double y0 = 0.0;
	private double xrec = x0 + (number_of_horizontal_sections - 1) * dx;

	private double rho = 1200;
	private double g = -9.81;
	private double E = 4e7;
	private double nu = 0.3;
	private double thick = 1.0;

	// private double yrec = y0 + number_of_vertical_sections * dy;

	private int step = 0;
	GidPostStructural post;

	public Excavation2dDeactivation() {
		projectDir = "/home/hbui/kratos_janosch";
		projectName = "excavation2d.gid";
		post = new GidPostStructural(projectDir, projectName);
	}

	@Override
	public Mesh createMesh() {
		MeshGenerator p = new PatchMeshGenerator(number_of_horizontal_sections,
				number_of_vertical_sections, 0, 0, dx, dy);
		Mesh mesh = p.getMesh(2);
		return mesh;
	}

	@Override
	public Model createConditions(Model m) {
		Mesh mesh = m.getMesh();
		ArrayList<Node> nodes_bottom = MeshUtilities.seekNodesOnSurface(mesh, 0, 1, -y0);
		ArrayList<Node> nodes_left = MeshUtilities.seekNodesOnSurface(mesh, 1, 0, -x0);
		ArrayList<Node> nodes_right = MeshUtilities.seekNodesOnSurface(mesh, 1, 0, -xrec);

		Constraint cx = new Constraint(false, true);
		Constraint cy = new Constraint(true, false);

		mesh.addConstraint(cx, nodes_left);
		mesh.addConstraint(cx, nodes_right);
		mesh.addConstraint(cy, nodes_bottom);

		FunctionRnToR fy = new ConstantFunctionRnToR(rho * g);
		for (int i = 0; i < mesh.countFaces(); i++) {
			Face f = mesh.getFace(i);
			DistributedLoad l = new DistributedLoad(f, null, fy);
			m.addLoad(l);
		}

		return m;
	}

	@Override
	public MaterialModel createMaterial(Model m) {
		return new StVenantKirchhoffMM(E, nu, thick, rho, State.PLANE_STRAIN);
	}

	@Override
	public Element createElement(MeshPart mp, MaterialModel mm) {
		return new StructuralElement(mp, mm);
	}

	@Override
	public Model createModel() {
		Mesh mesh = createMesh();

		mesh.setNumberOfFields(mesh.getDimension());

		Model m = new Model(mesh);

		MaterialModel mm = createMaterial(m);

		for (int i = 0; i < mesh.countFaces(); i++) {
			Face f = mesh.getFace(i);
			Element e = createElement(f, mm);
			m.addElement(e);
		}

		m = createConditions(m);

		return m;
	}

	@Override
	public void postProcess(Model m) {

		// super.postProcess(m);

		try {
			post.writeMesh(m, step);
			post.writeNodalDisplacementResults(m, step);
		} catch (IOException e) {
			throw new Error("write failed");
		}

	}

	@Override
	public void run() {
		Model m = createModel();

		Analysis an = new LinearStaticAnalysis(m);
		// ((NewtonRaphsonBasedStrategy) an.getStrategy())
		// .setMaxNewtonRaphsonIteration(1);
		// an.getStrategy().setSolverType(SolverType.BAITSCH_SOLVER_GENERIC);
		an.getStrategy().setEchoLevel(EchoLevelType.OUTPUT, EchoLevelType.AUX1);

		post.clearAllPostFiles();

		for (int i = 0; i < 6; i++) {
			/*
			 * deactivate elements
			 */
			double x = 2 * (step - 1) + 2;

			Debugger.watch("x = ", x);

			for (int j = 0; j < m.countElements(); j++) {
				Face f = (Face) m.getElement(j).getMeshPart();
				double[] c = f.computeCenter();
				if (c[1] > 2 && c[1] < 4 && c[0] < x) {
					f.getElement().deactivate();
				}
			}

			// for (int j = 0; j < m.getMesh().countFaces(); j++) {
			// Face f = m.getMesh().getFace(i);
			// Debugger.watch("f" + f.getId() + ": " + f.isActivated());
			// }

			an.run();

			postProcess(m);

			step++;
		}

	}

	public static void main(String[] args) {
		AbstractStructuralStaticDemo demo = new Excavation2dDeactivation();

		demo.run();

	}
}
